/*
 *   Copyright (c) 2010-2022, SIUFUNG
 */
package net.siufung.market.base.permit.controller;

import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.siufung.core.model.EnumsVo;
import net.siufung.core.model.VerifyRepeatDto;
import net.siufung.core.model.enums.DeletedEnum;
import net.siufung.core.model.enums.MethodEventEnum;
import net.siufung.core.page.PagerResult;
import net.siufung.core.result.Result;
import net.siufung.core.result.ResultFail;
import net.siufung.core.result.ResultOk;
import net.siufung.core.utils.CopyUtil;
import net.siufung.market.base.permit.controller.assembler.MenuAssembler;
import net.siufung.market.base.permit.controller.model.dto.MenuDto;
import net.siufung.market.base.permit.controller.model.dto.MenuSaveDto;
import net.siufung.market.base.permit.controller.model.dto.MenuTreeTableParams;
import net.siufung.market.base.permit.controller.model.dto.MenuUpdateDto;
import net.siufung.market.base.permit.controller.model.dto.page.MenuPageDto;
import net.siufung.market.base.permit.controller.model.vo.MenuVo;
import net.siufung.market.base.permit.controller.regulation.MenuCreateRegulation;
import net.siufung.market.base.permit.controller.regulation.MenuDeleteRegulation;
import net.siufung.market.base.permit.controller.regulation.MenuUpdateRegulation;
import net.siufung.market.base.permit.enums.AccessStates;
import net.siufung.market.base.permit.enums.MenuTypes;
import net.siufung.market.base.permit.mapper.IMenuMapper;
import net.siufung.market.base.permit.mapper.IPermitMapper;
import net.siufung.market.base.permit.mapper.entity.Menu;
import net.siufung.market.base.permit.service.IMenuQueryService;
import net.siufung.market.base.permit.service.IMenuService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * 系统菜单 前端控制器
 *
 * @author 陈建峰
 * @since 2022-07-05 22:19:50
 */
@Api(tags = "菜单管理")
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/sys/menu")
public class MenuController {

    private final IMenuMapper menuMapper;
    private final IMenuService menuService;
    private final IMenuQueryService menuQueryService;
    private final IPermitMapper permitMapper;

    /**
     * 通过主键获取 系统菜单
     * @param id 主键
     * @return Result<MenuVo>
     * */
    @ApiOperation(value = "通过Id获取系统菜单表信息")
    @GetMapping(value = "/id/{id}")
    public Result<MenuVo> getById(
            @PathVariable("id") Integer id) {
        return Result.ok(
            MenuAssembler.from(menuMapper.selectById(id)));
    }

    /**
     * 获取 系统菜单表列表
     * @param menuDto 属性
     * @return Result<List<MenuVo>>
     * */
    @ApiOperation(value = "获取系统菜单表列表")
    @PostMapping(value = "/list")
    public Result<List<MenuVo>> list(
            @RequestBody MenuDto menuDto) {
        return Result.ok(
            MenuAssembler.fromList(
                    menuMapper.selectList(Wrappers.query(menuDto.to()))));
    }

    /**
     * 获取 系统菜单表分页
     * @param menuPageDto 属性
     * @return 查询分页结果
     * */
    @ApiOperation(value = "获取系统菜单表分页")
    @PostMapping(value="/page")
    public Result<PagerResult<MenuVo>> getPage(
            @RequestBody MenuPageDto menuPageDto) {
        menuPageDto.validated();
        QueryWrapper<Menu> wrapper = new QueryWrapper<>();
                    wrapper.lambda().orderByDesc(Menu::getId);
        IPage<Menu> menuPage = menuMapper.selectPage(
                new Page<>(menuPageDto.getPageNo(), menuPageDto.getPageSize()), wrapper);
        PagerResult<MenuVo> menuVoPage = new PagerResult<MenuVo>(
                menuPage.getCurrent(), menuPage.getSize(), menuPage.getTotal());
        menuVoPage.setRecords(
            MenuAssembler.fromList(menuPage.getRecords()));
        return Result.ok(menuVoPage);
    }

    /**
     * 通过主键删除 系统菜单 对象
     * @param id 主键
     * @return 删除结果
     * */
    @ApiOperation(value = "删除系统菜单表对象")
    @PostMapping(value="/remove/{id}")
    public Result<Void> remove(
        @PathVariable("id") Integer id) {
        MenuDeleteRegulation menuDeleteRegulation = new MenuDeleteRegulation(menuMapper);
        menuDeleteRegulation.isSatisfiedBy(id);
        if(menuService.removeById(id)){
            return Result.ok(ResultOk.REMOVE);
        }
        return Result.fail(ResultFail.DATA_REMOVE_ERROR);
    }

    /**
     * 创建 系统菜单
     * @param menuSaveDto 对象属性
     * @return 创建结果
     * */
    @ApiOperation(value = "创建 系统菜单")
    @PostMapping(value="/create")
    public Result<Void> create(
            @RequestBody MenuSaveDto menuSaveDto) {
        menuSaveDto.validated();
        MenuCreateRegulation menuCreateRegulation = new MenuCreateRegulation(menuMapper, permitMapper);
        menuCreateRegulation.isSatisfiedBy(menuSaveDto);
        if(menuSaveDto.getAccessState()
                ?menuService.save(menuSaveDto.to(), menuSaveDto.convertPermitList())
                :menuService.save(menuSaveDto.to())){
            return Result.ok(ResultOk.ADD);
        }
        return Result.fail(ResultFail.DATA_ADD_ERROR);
    }

    /**
     * 更新 系统菜单
     * @param menuUpdateDto 对象属性
     * @return Result<Void>
     * */
    @ApiOperation(value = "更新 系统菜单 信息")
    @PostMapping(value="/update")
    public Result<Void> update(
            @RequestBody MenuUpdateDto menuUpdateDto) {
        menuUpdateDto.validated();
        MenuUpdateRegulation menuUpdateRegulation = new MenuUpdateRegulation(menuMapper);
        menuUpdateRegulation.isSatisfiedBy(menuUpdateDto);
        Menu menuOf = menuService.getById(menuUpdateDto.getId());
        CopyUtil.copyPropertiesIgnoreNull(menuUpdateDto.to(), menuOf);
        if(menuUpdateDto.getAccessState()
                ?menuService.updateById(menuOf, menuUpdateDto.convertPermitList())
                :menuService.updateById(menuOf)){
            return Result.ok(ResultOk.UPDATE);
        }
        return Result.fail(ResultFail.DATA_UPDATE_ERROR);
    }

    /**
     * 更新 系统菜单 状态
     * @param id 主键
     * @param deleted 数据状态
     * @return Result<Void>
     * */
    @ApiOperation(value = "更新 系统菜单 状态")
    @PostMapping(value="/status/{id}/{deleted}")
    public Result<Void> updateStatusById(
            @PathVariable("id") Integer id,
            @PathVariable("deleted") boolean deleted) {
        if(menuService.updateStatusById(id, DeletedEnum.get(deleted))){
            return Result.ok(ResultOk.STATUS);
        }
        return Result.fail(ResultFail.DATA_UPDATE_ERROR);
    }

    /**
     * 获取菜单树
     * @param parentId 父级
     * @param hasAccess 是否包含可执行
     * @return Result<List<Tree<Integer>>>
     */
    @ApiOperation(value = "获取菜单树", notes = "")
    @GetMapping(value = "/getTreeList")
    public Result<List<Tree<Integer>>> getTreeList(
            @RequestParam(value = "clientId", required = false) String clientId,
            @RequestParam(value = "parentId", required = false) Integer parentId,
            @RequestParam("hasAccess") boolean hasAccess) {
        return Result.ok(menuQueryService.getTreeList(clientId, parentId, hasAccess));
    }

    /**
     * 获取系统菜单树
     * @param menuTreeTableParams 菜单树表格参数
     * @return Result<List<MenuTreeTableVo>>
     * */
    @ApiOperation(value = "获取系统菜单树")
    @PostMapping(value = "/getTreeTable")
    public Result<List<Tree<Integer>>> getTreeTable(@RequestBody MenuTreeTableParams menuTreeTableParams) {
        return Result.ok(menuQueryService.getTreeTable(menuTreeTableParams));
    }

    /**
     * 获取 获取菜单访问类型列表
     * @return Result<List<EnumsVo>>
     * */
    @ApiOperation(value = "获取菜单访问类型列表")
    @GetMapping(value = "/getAccessStateList")
    public Result<List<EnumsVo>> getAccessStateList() {
        return Result.ok(AccessStates.getList());
    }

    /**
     * 获取 获取菜单类型列表
     * @return Result<List<EnumsVo>>
     * */
    @ApiOperation(value = "获取菜单类型列表")
    @GetMapping(value = "/getMenuTypeList")
    public Result<List<EnumsVo>> getMenuTypeList() {
        return Result.ok(MenuTypes.getList());
    }

    /**
     * 判断名称是否重复
     * @param menuName 名称
     * @param event 事件
     * @param id Key
     * @return Result<Boolean>
     */
    @ApiOperation(value = "判断名称是否重复", notes = "")
    @PostMapping(value="/checkNameRepeat")
    public Result<Boolean> checkNameRepeat(
            @RequestParam("menuName") String menuName,
            @RequestParam(value = "event") String event,
            @RequestParam(value = "id", required = false) Integer id) {
        VerifyRepeatDto<Integer> verifyRepeatDto = new VerifyRepeatDto<>();
        verifyRepeatDto.setVerifyKeyValue(menuName);
        verifyRepeatDto.setMethodEventEnum(MethodEventEnum.get(event));
        verifyRepeatDto.setPk(id);
        boolean notRepeat = menuMapper.checkMenuNameRepeat(verifyRepeatDto);
        if(notRepeat){
            return Result.ok("菜单名称可用!");
        }
        return Result.fail(ResultFail.PARAM_REPEAT_ERROR);
    }

    /**
     * 判断路由是否重复
     * @param router 路由
     * @param event 事件
     * @param id Key
     * @return Result<Boolean>
     */
    @ApiOperation(value = "判断路由是否重复", notes = "")
    @PostMapping(value="/checkRouterRepeat")
    public Result<Boolean> checkRouterRepeat(
            @RequestParam("router") String router,
            @RequestParam(value = "event") String event,
            @RequestParam(value = "id", required = false) Integer id) {
        VerifyRepeatDto<Integer> verifyRepeatDto = new VerifyRepeatDto<>();
        verifyRepeatDto.setVerifyKeyValue(router);
        verifyRepeatDto.setMethodEventEnum(MethodEventEnum.get(event));
        verifyRepeatDto.setPk(id);
        boolean notRepeat = menuMapper.checkMenuRouterRepeat(verifyRepeatDto);
        if(notRepeat){
            return Result.ok("菜单路由可用!");
        }
        return Result.fail(ResultFail.PARAM_REPEAT_ERROR);
    }

    /**
     * 判断权限标识是否重复
     * @param sign 权限标识
     * @param event 事件
     * @param id Key
     * @return Result<Boolean>
     */
    @ApiOperation(value = "判断权限标识是否重复", notes = "")
    @PostMapping(value="/checkSignRepeat")
    public Result<Boolean> checkSignRepeat(
            @RequestParam("sign") String sign,
            @RequestParam(value = "event") String event,
            @RequestParam(value = "id", required = false) Integer id) {
        VerifyRepeatDto<Integer> verifyRepeatDto = new VerifyRepeatDto<>();
        verifyRepeatDto.setVerifyKeyValue(sign);
        verifyRepeatDto.setMethodEventEnum(MethodEventEnum.get(event));
        verifyRepeatDto.setPk(id);
        boolean notRepeat = menuMapper.checkMenuSignRepeat(verifyRepeatDto);
        if(notRepeat){
            return Result.ok("菜单权限标识可用!");
        }
        return Result.fail(ResultFail.PARAM_REPEAT_ERROR);
    }

}